package net.mayee.alice.web.controller.admin.system;

import jodd.props.Props;
import net.mayee.alice.common.Definiens;
import net.mayee.alice.entity.admin.account.Language;
import net.mayee.alice.entity.admin.account.Role;
import net.mayee.alice.entity.admin.account.User;
import net.mayee.alice.filter.ShiroAdminDbRealm;
import net.mayee.alice.functions.ui.UIFunction;
import net.mayee.alice.web.controller.base.BaseController;
import net.mayee.common.AliceHelper;
import net.mayee.common.CoderHelper;
import net.mayee.common.Uploader;
import net.mayee.datatables.DtBean;
import net.mayee.leo.LeoEncrypt;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.json.JSONArray;
import org.json.JSONException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Controller
public class UserController extends BaseController {

    @RequiresPermissions("user:R")
    @RequestMapping(value = "/sdm/sys/user/R")
    public String userR(Model model) {
        model.addAttribute("userStatusList", CoderHelper.getInstance().getUserStatusItemList());
        return "system/user/userR";
    }

    @RequiresPermissions(value = {"user:RESET_PASSWORD"})
    @RequestMapping(value = "/sys/user/ajax/RPW", method = RequestMethod.POST)
    public void resetPasswordAjax(HttpServletResponse response, HttpServletRequest request,
                                  Model model) throws IOException, JSONException {
        List<String> errorMsgList = new ArrayList<String>();

        String en_pw1 = request.getParameter("resetPassword1");
        String en_pw2 = request.getParameter("resetPassword2");
        String uid = request.getParameter("uid");

        /* decrypt password */
        Props props = AliceHelper.getInstance().getJoddProps();
        String privateExponent = props.getValue("encrypt.rsa.private.exponent");
        String modulus = props.getValue("encrypt.rsa.modulus");

        byte[] de_password1 = null;
        byte[] de_password2 = null;
        try {
            de_password1 = LeoEncrypt.easyDecryptRSAByProviderPirvateKey(
                    modulus,
                    privateExponent,
                    new org.bouncycastle.jce.provider.BouncyCastleProvider(),
                    new BigInteger(en_pw1, 16).toByteArray()
            );
            de_password2 = LeoEncrypt.easyDecryptRSAByProviderPirvateKey(
                    modulus,
                    privateExponent,
                    new org.bouncycastle.jce.provider.BouncyCastleProvider(),
                    new BigInteger(en_pw2, 16).toByteArray()
            );
        } catch (Exception e) {
            e.printStackTrace();
        }

        String pw1 = StringUtils.reverse(new String(de_password1));
        String pw2 = StringUtils.reverse(new String(de_password2));

        if (LOGIN_PASSWORD_PATTERN.matcher(pw1).matches()) {
            if (pw1.equals(pw2)) {
                User user = this.getUserService().getUser(uid);
                if (user != null) {
                    User u = new User();
                    u.setUuid(user.getUuid());
                    u.setPlainPassword(pw1);
                    this.getUserService().resetPassword(u);
                } else {
                    errorMsgList.add(
                            this.getMessage("net.mayee.alice.msg.sys.user.user_does_not_exist", "用户不存在！"));
                }
            } else {
                errorMsgList.add(
                        this.getMessage("net.mayee.alice.msg.sys.user.pwdif",
                                new String[]{this.getMessage("net.mayee.alice.web.sys.user.confirm_password")},
                                "[ 确认密码 ] 两次输入不一致；"));
            }
        } else {
            errorMsgList.add(
                    this.getMessage("net.mayee.alice.msg.sys.user.pw_error",
                            new String[]{this.getMessage("net.mayee.alice.web.sys.user.password")},
                            "[ 密码 ] 只能包含大小写字母、数字和下划线，长度4 ~ 16个字符；"));
        }
        request.setAttribute("reJSON",
                this.getAjaxRegisterJSONString(errorMsgList,
                        this.getMessage("net.mayee.alice.msg.sys.user.reset_password_success", "密码重置成功！")));
    }

    @RequiresPermissions(value = {"user:UPDATE_PHOTO"})
    @RequestMapping(value = "/sys/user/ajax2/PUL", method = RequestMethod.POST)
    public void userPhotoUploadAjax(HttpServletResponse response, HttpServletRequest request,
                                    Model model) throws Exception {
        List<String> errorMsgList = new ArrayList<String>();
        request.setCharacterEncoding(Uploader.DEFAULT_CHARSET);
        response.setCharacterEncoding(Uploader.DEFAULT_CHARSET);

        Uploader up = new Uploader(request, Uploader.UPLOAD_TYPE_IMAGE);
        up.upload();
        if ("SUCCESS".equals(up.getState())) {
            File picture = new File(this.getRealPath(getRequest()) + up.getUrl());
            BufferedImage sourceImg = ImageIO.read(new FileInputStream(picture));
            if (sourceImg != null) {
                if (sourceImg.getWidth() <= 200 && sourceImg.getHeight() <= 200) {
                    /* update user photo */
                    String uid = up.getParameter("uid");
                    if (uid != null) {
                        User user = this.getUserService().getUser(uid);
                        if (user != null) {
                            User u = new User();
                            u.setUuid(user.getUuid());
                            u.setPhotoImg(up.getUrl());
                            this.getUserService().updateUser(u, null);
                        } else {
                            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.user_does_not_exist", "用户不存在！"));
                        }
                    } else {
                        errorMsgList.add(this.getMessage("net.mayee.alice.error.data_error", "数据异常！"));
                    }
                } else {
                    errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.photo_maxsize_200", "图片尺寸不能大于 200＊200 像素"));
                }
            } else {
                errorMsgList.add(this.getMessage("net.mayee.alice.error.load_img_error", "图片载入异常！"));
            }
            if (errorMsgList.size() > 0) {
                picture.delete();
            }
        } else {
            errorMsgList.add(this.getMessage(up.getState()));
        }

        response.getWriter().write(
                this.getAjaxUpdateJSONString(errorMsgList,
                        this.getMessage("net.mayee.alice.global.save_success", "保存成功！")));
    }

    @RequiresPermissions(value = {"user:U"})
    @RequestMapping(value = "/sys/user/ajax/OnA/{u}", method = RequestMethod.POST)
    public void userOnAAjax(@PathVariable(value = "u") String uid,
                            HttpServletResponse response, HttpServletRequest request,
                            Model model) throws IOException, JSONException {
        List<String> errorMsgList = new ArrayList<String>();

        if (UIFunction.isSuperAdmin()) {
            User user = this.getUserService().getUser(uid);
            if (user != null) {
                if (user.getStatusCode() == Definiens.STATUS_CODE_USER_LOCKED) {
                    errorMsgList.add(this.getMessage("net.mayee.alice.error.cannot_for_lock_user", "无法操作已锁定用户，请先解锁！"));
                } else {
                    if (user.getStatusCode() == Definiens.STATUS_CODE_USER_NORMAL) {
                        User u = new User();
                        u.setUuid(uid);
                        u.setStatusCode(Definiens.STATUS_CODE_USER_ADMIN);
                        this.getUserService().updateUser(u, null);
                    } else {
                        errorMsgList.add(this.getMessage("net.mayee.alice.error.data_error", "数据异常！"));
                    }
                }
            } else {
                errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.user_does_not_exist", "用户不存在！"));
            }
        } else {
            errorMsgList.add(this.getMessage("net.mayee.alice.error.no_permission", "权限不足！"));
        }

        response.getWriter().write(
                this.getAjaxUpdateJSONString(errorMsgList,
                        this.getMessage("net.mayee.alice.global.save_success", "保存成功！")));
    }

    @RequiresPermissions(value = {"user:U"})
    @RequestMapping(value = "/sys/user/ajax/OffA/{u}", method = RequestMethod.POST)
    public void userOffAAjax(@PathVariable(value = "u") String uid,
                             HttpServletResponse response, HttpServletRequest request,
                             Model model) throws IOException, JSONException {
        List<String> errorMsgList = new ArrayList<String>();

        if (UIFunction.isSuperAdmin()) {
            User user = this.getUserService().getUser(uid);
            if (user != null) {
                if (user.getStatusCode() == Definiens.STATUS_CODE_USER_LOCKED) {
                    errorMsgList.add(this.getMessage("net.mayee.alice.error.cannot_for_lock_user", "无法操作已锁定用户，请先解锁！"));
                } else {
                    if (user != null && user.getStatusCode() == Definiens.STATUS_CODE_USER_ADMIN) {
                        User u = new User();
                        u.setUuid(uid);
                        u.setStatusCode(Definiens.STATUS_CODE_USER_NORMAL);
                        this.getUserService().updateUser(u, null);
                    } else {
                        errorMsgList.add(this.getMessage("net.mayee.alice.error.data_error", "数据异常！"));
                    }
                }
            } else {
                errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.user_does_not_exist", "用户不存在！"));
            }
        } else {
            errorMsgList.add(this.getMessage("net.mayee.alice.error.no_permission", "权限不足！"));
        }

        response.getWriter().write(
                this.getAjaxUpdateJSONString(errorMsgList,
                        this.getMessage("net.mayee.alice.global.save_success", "保存成功！")));
    }

    @RequiresPermissions(value = {"user:U"})
    @RequestMapping(value = "/sys/user/ajax/U", method = RequestMethod.POST)
    public void userUAjax(@ModelAttribute("user") User user,
                          HttpServletResponse response, HttpServletRequest request,
                          Model model) throws IOException, JSONException {
        List<String> errorMsgList = validator(user);

        /* 验证uuid是否合法 */
        User cUser = this.getUserService().getUser(user.getUuid());
        if (cUser != null) {
            Integer userStatusCode = cUser.getStatusCode();
            /* 无法修改管理员信息 */
            if (Definiens.STATUS_CODE_USER_ADMIN != userStatusCode
                    && Definiens.STATUS_CODE_USER_SUPER_ADMIN != userStatusCode) {
                /* 验证角色 */
                String roleString = request.getParameter("roleSel");
                if (StringUtils.isNotBlank(roleString) && StringUtils.split(roleString, ",").length < 4) {
                    Subject currentUser = SecurityUtils.getSubject();
                    ShiroAdminDbRealm.ShiroUser shiroUser = (ShiroAdminDbRealm.ShiroUser) currentUser.getPrincipal();

                    cUser.setName(user.getName());
                    cUser.setPhone(user.getPhone());
                    cUser.setEmail(user.getEmail());

                    int newUserStatusCode = 3;
                    if (user.getStatusCode() == null) {
                        newUserStatusCode = 0;
                    }
                    cUser.setStatusCode(newUserStatusCode);
                    int lagId = user.getLanguage().getId();
                    cUser.getLanguage().setId(lagId);
                    this.getUserService().updateUser(cUser, roleString);

                    //change language
                    Language lag = this.getLanguageService().getLanguage(lagId);
                    this.setSessionLocale(lag.getCode());

                    shiroUser.setLagCode(lag.getCode());
                } else {
                    errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.max_role",
                            new String[]{this.getMessage("net.mayee.alice.web.sys.user.role")},
                            "[ 角色 ] 必填项，最多可选三个角色；"));
                }
            } else {
                errorMsgList.add(this.getMessage("net.mayee.alice.error.no_permission", "权限不足！"));
            }
        } else {
            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.user_does_not_exist", "用户不存在！"));
        }

        request.setAttribute("reJSON",
                this.getAjaxUpdateJSONString(errorMsgList,
                        this.getMessage("net.mayee.alice.global.save_success", "保存成功！")));
    }

    @RequiresPermissions(value = {"user:R"})
    @RequestMapping(value = "/sys/user/ajax/R")
    public void userRAjax(HttpServletResponse response, HttpServletRequest request) throws Exception {

        JSONArray array = new JSONArray();
        DtBean dtBean = new DtBean(request);

        int totalRecords = this.getUserService().count(new HashMap<String, Object>());
        int totalDisplayRecords = totalRecords;
        if (dtBean.isHasSearch()) {
            totalDisplayRecords = this.getUserService().count(dtBean.getSearchParams());
        }

        List<User> list = this.getUserService().searchByLimit(dtBean.getSearchParams());
        for (int i = 0; i < list.size(); i++) {
            User user = list.get(i);
            JSONArray ja = new JSONArray();
            if (user.isAdmin()) {
                if (UIFunction.isSuperAdmin()) {
                    ja.put("<a style=\"text-decoration: underline;\" href=\"" + getPath() + "/sys/user/" + user.getUuid() + "\">" + user.getLoginName() + "</a>");
                } else {
                    ja.put(user.getLoginName());
                }
            } else if (user.isSuperAdmin()) {
                ja.put(user.getLoginName());
            } else {
                ja.put("<a style=\"text-decoration: underline;\" href=\"" + getPath() + "/sys/user/" + user.getUuid() + "\">" + user.getLoginName() + "</a>");
            }
            ja.put(user.getName());
            ja.put(user.getPhone());
            ja.put(user.getEmail());
            ja.put(UIFunction.printUserStatusTextLabel(this.getRequest(), user.getStatusCode()));
            array.put(ja);
        }

        request.setAttribute("reJSON", dtBean.getJSONString(array, totalRecords, totalDisplayRecords));
    }

    @RequiresPermissions(value = {"user:D"})
    @RequestMapping(value = "/sys/user/ajax/D/{u}", method = RequestMethod.POST)
    public void userDAjax(@PathVariable(value = "u") String uid, HttpServletResponse response,
                          HttpServletRequest request, Model model) throws IOException, JSONException {
        List<String> errorMsgList = new ArrayList<String>();
        User user = this.getUserService().getUser(uid);
        if (user != null) {
            /* 如果此用户已被分配到某些角色下，全部清除 */
            this.getUserService().removeUser(user.getUuid());
        } else {
            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.user_does_not_exist", "用户不存在！"));
        }
        request.setAttribute("reJSON",
                this.getAjaxUpdateJSONString(errorMsgList,
                        this.getMessage("net.mayee.alice.global.delete_success", "删除成功！")));
    }

    @RequiresPermissions(value = {"user:R"})
    @RequestMapping(value = "/sys/user/{u}")
    public String userU(@PathVariable(value = "u") String uid, Model model) {
        Props props = AliceHelper.getInstance().getJoddProps();

        User user = this.getUserService().getUser(uid);
        if (user == null || (user.isAdmin() && !UIFunction.isSuperAdmin())) {
            return "redirect:/sdm/sys/user/R";
        }

        StringBuilder sb = new StringBuilder();
            /* get all roles */
        List<Role> roleList = this.getRoleService().getAll();
        for (Role role : roleList) {
            sb.append("\"" + role.getRoleKey() + "\",");
        }
        model.addAttribute("rolesString",
                sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "");

        StringBuilder sb_c = new StringBuilder();
        List<Role> roleChooseList = this.getRoleService().getRolesByUser(uid);
        for (Role role : roleChooseList) {
            sb_c.append(role.getRoleKey() + ",");
        }
        model.addAttribute("rolesChooseString",
                sb_c.length() > 0 ? sb_c.substring(0, sb_c.length() - 1) : "");

        List<Language> lagList = this.getLanguageService().getAll();
        model.addAttribute("lagList", lagList);

        model.addAttribute("user", user);
        model.addAttribute("rsa_modulus", props.getValue("encrypt.rsa.modulus"));
        model.addAttribute("rsa_exponent", props.getValue("encrypt.rsa.public.exponent"));
        return "system/user/userU";
    }

    @RequiresPermissions(value = {"user:C"})
    @RequestMapping(value = "/sys/user/C")
    public String userC(Model model) {
        StringBuilder sb = new StringBuilder();
        List<Role> roleList = this.getRoleService().getAll();
        for (Role role : roleList) {
            sb.append("\"" + role.getRoleKey() + "\",");
        }
        model.addAttribute("rolesString",
                sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "");

        List<Language> lagList = this.getLanguageService().getAll();
        model.addAttribute("lagList", lagList);

        return "system/user/userC";
    }

    @RequiresPermissions(value = {"user:C"})
    @RequestMapping(value = "/sys/user/ajax/C", method = RequestMethod.POST)
    public void userCAjax(@ModelAttribute("user") User user, HttpServletResponse response,
                          HttpServletRequest request, Model model) throws IOException, JSONException {
        List<String> errorMsgList = validator(user);

        String roleString = request.getParameter("roleSel");
        if (StringUtils.isBlank(roleString) || StringUtils.split(roleString, ",").length > 3) {
            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.max_role",
                    new String[]{this.getMessage("net.mayee.alice.web.sys.user.role")},
                    "[ 角色 ] 必填项，最多可选三个角色；"));
        }

        if (this.getUserService().getByLoginName(user.getLoginName().trim()) != null) {
            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.username_exist",
                    new String[]{user.getLoginName()}, "[ " + user.getLoginName() + " ] 已存在；"));
        }

        if (errorMsgList.size() < 1) {
            user.setPhotoImg(AliceHelper.getInstance().getJoddProps().getValue("system.default.photo"));
            this.getUserService().insertUser(user, roleString);
        }

        String successMsg = this.getMessage("net.mayee.alice.msg.sys.user.create_user_success",
                new String[]{user.getLoginName()}, "新增用户 [ " + user.getLoginName() + " ] 成功！");
        request.setAttribute("reJSON",
                this.getAjaxRegisterJSONString(errorMsgList, successMsg));
    }

    private List<String> validator(User user) {
        List<String> errorMsgList = new ArrayList<String>();

        if (StringUtils.isEmpty(user.getUuid())) {
            if (!LOGIN_NAME_PATTERN.matcher(user.getLoginName().trim()).matches()) {
                errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.username_error",
                        new String[]{this.getMessage("net.mayee.alice.web.sys.user.username")},
                        "[ 用户名 ] 只能包含大小写字母和数字，长度4 ~ 20个字符；"));
            }

            if (!LOGIN_PASSWORD_PATTERN.matcher(user.getLoginPassword().trim()).matches()) {
                errorMsgList.add(
                        this.getMessage("net.mayee.alice.msg.sys.user.pw_error",
                                new String[]{this.getMessage("net.mayee.alice.web.sys.user.password")},
                                "[ 密码 ] 只能包含大小写字母、数字和下划线，长度4 ~ 16个字符；"));
            }

            if (!user.getLoginPassword().trim().equals(user.getPlainPassword().trim())) {
                errorMsgList.add(
                        this.getMessage("net.mayee.alice.msg.sys.user.pwdif",
                                new String[]{this.getMessage("net.mayee.alice.web.sys.user.confirm_password")},
                                "[ 确认密码 ] 两次输入不一致；"));
            }
        }

        if (!EMAIL_PATTERN.matcher(user.getEmail().trim()).matches()) {
            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.email_error",
                    new String[]{this.getMessage("net.mayee.alice.web.sys.user.email")},
                    "[ 电子邮箱 ] 请输入合法的邮箱地址；"));
        }

        String name = user.getName().trim();
        if (name.length() < 2 || name.length() > 10) {
            errorMsgList.add(this.getMessage("net.mayee.alice.msg.sys.user.name_error",
                    new String[]{this.getMessage("net.mayee.alice.web.sys.user.name")},
                    "[ 姓名 ] 长度在2 ~ 10个字符之间；"));
        }

        return errorMsgList;
    }

    /**
     * 普通用户不可修改admin和superadmin
     * 只有superadmin可修改admin
     *
     * @param user
     * @return
     */
    private boolean adminUpdateCheck(User user) {
        if (user.getStatusCode() == Definiens.STATUS_CODE_USER_ADMIN) {
            return UIFunction.isAdmin();
        } else if (user.getStatusCode() == Definiens.STATUS_CODE_USER_SUPER_ADMIN) {
            return UIFunction.isSuperAdmin();
        } else {
            return true;
        }
    }

}
